package com.smartwebx.ha.biz.assign.impl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.sym.Name;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import com.smartwebx.ha.biz.assign.HaStationAreaManager;
import com.smartwebx.ha.dal.assign.bean.HaStationArea;
import com.smartwebx.ha.dal.assign.bean.HaStationAreaExample;
import com.smartwebx.ha.dal.assign.bean.HaStationAreaExample.Criteria;
import com.smartwebx.ha.dal.assign.bean.HaStationGroupCfg;
import com.smartwebx.ha.dal.assign.bean.HaStationGroupCfgExample;
import com.smartwebx.ha.dal.assign.bean.HaStationStationGroup;
import com.smartwebx.ha.dal.assign.bean.HaStationStationGroupExample;
import com.smartwebx.ha.dal.assign.bean.HaUser;
import com.smartwebx.ha.dal.assign.dao.HaAdminAreaMapper;
import com.smartwebx.ha.dal.assign.dao.HaStationAreaMapper;
import com.smartwebx.ha.dal.assign.dao.HaStationGroupCfgMapper;
import com.smartwebx.ha.dal.assign.dao.HaStationStationGroupMapper;
import com.smartwebx.ha.dal.config.StatGroupThreadLocal;
import com.smartwebx.ha.dal.realtime.dao.StationMapper;
import com.smartwebx.ha.dal.usebean.StationAdminArea;
import com.smartwebx.ha.dal.util.MyFunctions;

@Service
public class HaStationAreaManagerImpl implements HaStationAreaManager {
	@Autowired
	private HaStationAreaMapper haStationAreaDao;
	@Autowired
	private HaAdminAreaMapper haAdminAreaDao;
	@Autowired
	private StationMapper rainWaterStationDao;
	@Autowired
	private HaStationStationGroupMapper haStationStationGroupDao;
	@Autowired
	private HaStationGroupCfgMapper haStationGroupCfgDao;

	@Override
	public List<HaStationArea> getStationAreaByAreaId(Integer areaId) {
		HaStationAreaExample statAreaExample = new HaStationAreaExample();
		statAreaExample.createCriteria().andAreaIdEqualTo(areaId);
		List<HaStationArea> findStatAreas = haStationAreaDao
				.selectByExample(statAreaExample);
		return findStatAreas;
	}

	@Override
	public SetMultimap<Integer, String> getAreaStarGroupMap() {
		List<HaStationArea> allStatArea = haStationAreaDao
				.selectByExample(new HaStationAreaExample());
		List<HaStationGroupCfg> allStatGroupCfg = haStationGroupCfgDao
				.selectByExample(new HaStationGroupCfgExample());

		SetMultimap<Integer, String> result = LinkedHashMultimap.create();
		for (HaStationArea haStationArea : allStatArea) {
			result.put(haStationArea.getAreaId(), haStationArea.getStationId());
		}

		for (HaStationGroupCfg statGroupCfg : allStatGroupCfg) {
			result.put(statGroupCfg.getAreaId(), statGroupCfg.getCode());
		}
		return result;
	}

	/**
	 * 根据用户所属区域获得区域下的所有站码
	 * 
	 * @param areaId
	 * @return
	 */
	private List<String> getStationIdsByAreaId(
			List<HaStationArea> findStationByAreaId) {
		List<String> findStationIds = Lists.newArrayList();
		for (HaStationArea haStationArea : findStationByAreaId) {
			findStationIds.add(haStationArea.getStationId());
		}
		return findStationIds;
	}

	private List<HaStationArea> getStationByAreaId(int areaId) {
		HaStationAreaExample haStationAreaExample = new HaStationAreaExample();
		haStationAreaExample.createCriteria().andAreaIdEqualTo(areaId);
		List<HaStationArea> findStationByAreaId = haStationAreaDao
				.selectByExample(haStationAreaExample);
		return findStationByAreaId;
	}

	@Override
	public Collection<StationAdminArea> getStationsByAdminArea(int areaId) {
		// 找到所有已经存在的站码
		List<String> checkedStationIds = this
				.getStationIdsByAreaId(getStationByAreaId(areaId));

		// 查询所有行政区域
		Collection<StationAdminArea> adminAreas = haAdminAreaDao.findAll();
		// 查询所有水雨情站
		Collection<StationAdminArea> rainWaterStations = rainWaterStationDao
				.getAllBaseStationInfo();

		Collection<StationAdminArea> allStation = Lists
				.newArrayList(adminAreas);

		Collection<StationAdminArea> notFindStations = Lists.newArrayList();
		Collection<StationAdminArea> otherAdminAreas = Lists.newArrayList();

		for (final StationAdminArea rainWaterStation : rainWaterStations) {
			String statId = rainWaterStation.getId();
			if (checkedStationIds.contains(statId))
				rainWaterStation.setChecked(true);

			if (this.compAreaId(adminAreas, rainWaterStation.getParentId(), 0)) {
				notFindStations.add(rainWaterStation);
			} else {
				allStation.add(rainWaterStation);
				/*StationAdminArea haAdminArea = haAdminAreaDao.findByParentId(rainWaterStation.getParentId());
				if(haAdminArea==null){
					Collection<StationAdminArea> haAdminAreaLists = haAdminAreaDao.findAllWhere(rainWaterStation.getAdmauth().replace(" ", "")+"市");
					if(haAdminAreaLists.size()==1){
						for(StationAdminArea haAdminAreaList : haAdminAreaLists){
							rainWaterStation.setParentId(haAdminAreaList.getId());
							allStation.add(rainWaterStation);
						}
					}
				}else{
					allStation.add(rainWaterStation);
				}*/
			}
		}

		for (StationAdminArea notFindStation : notFindStations) {
			String statParentId = notFindStation.getParentId();
			String id, parentId;
			int leven = 0;
			if (statParentId == null) {
				id = "999999";
				parentId = "0";
			} else {
				parentId = StringUtils.substring(statParentId, 0, 2);
				id = parentId + "0999";
				parentId += "0000";
				leven = 1;
			}

			notFindStation.setParentId(id);
			if (this.compAreaId(otherAdminAreas, id, 0)) {
				otherAdminAreas.add(new StationAdminArea(id, parentId, "其他",
						leven));
			}
		}

		allStation.addAll(notFindStations);
		allStation.addAll(otherAdminAreas);

		Collection<StationAdminArea> validStations = Collections2.filter(
				allStation, new Predicate<StationAdminArea>() {
					public boolean apply(StationAdminArea point) {
						int childs = point.getChilds();
						char statType = point.getStatType();
						return (statType == '0' && childs > 0)
								|| (statType == '1');
					}
				});

		return validStations;
	}

	@Override
	public Collection<StationAdminArea> getAreaStationsByAdminArea(int areaId,
			int statGroupId) {
		Collection<StationAdminArea> adminAreas = haAdminAreaDao.findAll();

		// 用户区域下的所有站码
		List<HaStationArea> stationAreas = this.getStationByAreaId(areaId);
		List<String> stationAreaIds = this.getStationIdsByAreaId(stationAreas);
		Collection<StationAdminArea> stationAdminAreas = rainWaterStationDao
				.getBaseStationInfosInQuery(stationAreaIds);

		HaStationStationGroupExample haStationStationGroupExample = new HaStationStationGroupExample();
		haStationStationGroupExample.createCriteria().andStationGroupIdEqualTo(
				statGroupId);
		List<HaStationStationGroup> checkedStatStatGroups = haStationStationGroupDao
				.selectByExample(haStationStationGroupExample);

		List<Integer> statIds = Lists.transform(stationAreas,
				MyFunctions.getIntIdFuns());
		Map<String, Integer> rainWaterIdAndStatId = Maps.newHashMap();
		for (HaStationArea stationArea : stationAreas) {
			rainWaterIdAndStatId.put(stationArea.getStationId(),
					stationArea.getId());
		}

		List<String> exitsStation = Lists.newArrayList();
		for (HaStationStationGroup statStatGroup : checkedStatStatGroups) {
			Integer statId = statStatGroup.getStatId();
			int index = statIds.indexOf(statId);
			exitsStation.add(stationAreas.get(index).getStationId());
		}

		Set<String> adminAreaCode = Sets.newHashSet();
		for (StationAdminArea stationAdminArea : stationAdminAreas) {
			String id = stationAdminArea.getId();
			if (exitsStation.contains(id)) {
				stationAdminArea.setChecked(true);
			}

			stationAdminArea.setStatId(rainWaterIdAndStatId.get(id));
			adminAreaCode.add(stationAdminArea.getParentId());
		}
		Collection<StationAdminArea> allParents = Lists.newArrayList();
		final Collection<String> otherCode = Lists.newArrayList();
		for (String code : adminAreaCode) {
			if (!this.findParentsByParentId(adminAreas, allParents, code))
				otherCode.add(code);
		}

		if (!otherCode.isEmpty()) {
			Collection<StationAdminArea> findOtherAdminAreas = Collections2
					.filter(stationAdminAreas,
							new Predicate<StationAdminArea>() {
						public boolean apply(StationAdminArea input) {
							return otherCode.contains(input
									.getParentId());
						}
					});

			for (StationAdminArea findOtherAdminArea : findOtherAdminAreas) {
				String statParentId = findOtherAdminArea.getParentId();
				String id, parentId;
				int leven = 0;
				if (statParentId == null) {
					id = "999999";
					parentId = "0";
				} else {
					parentId = StringUtils.substring(statParentId, 0, 2);
					id = parentId + "0999";
					parentId += "0000";
					leven = 1;
				}
				findOtherAdminArea.setParentId(id);
				StationAdminArea newAdminArea = new StationAdminArea(id,
						parentId, "其他", leven);
				if (!allParents.contains(newAdminArea)) {
					allParents.add(newAdminArea);
				}
				if (leven == 1) {
					this.findParentsByParentId(adminAreas, allParents, parentId);
				}
			}
		}
		stationAdminAreas.addAll(allParents);

		return stationAdminAreas;
	}

	/**
	 * 根据父Id找到所有的父节点
	 * 
	 * @param parentId
	 * @return
	 */
	private boolean findParentsByParentId(
			Collection<StationAdminArea> adminAreas,
			Collection<StationAdminArea> parents,String parentId) {
		final String parentIdFinal = parentId;
		Optional<StationAdminArea> stationAdminArea = Iterables.tryFind(adminAreas,
				new Predicate<StationAdminArea>() {
			public boolean apply(StationAdminArea input) {
				return Objects.equal(input.getId(), parentIdFinal);
			}
		});

		if (!stationAdminArea.isPresent()) {
			return false;
		} else if (!Collections2.transform(parents, MyFunctions.getStrIdFuns())
				.contains(parentId)) {
			parents.add(stationAdminArea.get());
		}
		parentId = stationAdminArea.get().getParentId();
		if (!Objects.equal(parentId, "0")) {
			this.findParentsByParentId(adminAreas, parents, parentId);
		}
		return true;
	}

	/**
	 * 如果返回true，则表示要查询的站不在行政区中
	 * 
	 * @param adminAreas
	 * @param findKey
	 * @param repeatNum
	 * @return
	 */
	private Boolean compAreaId(Collection<StationAdminArea> adminAreas,
			String findKey, int repeatNum) {
		//String findKey = stationAdminArea.getParentId();
		Optional<StationAdminArea> findPoint = Iterables.tryFind(adminAreas,
				this.findPred(findKey));
		if (findPoint.isPresent()) {
			StationAdminArea findStationAdminArea = findPoint.get();
			int childs = findStationAdminArea.getChilds();
			findStationAdminArea.setChilds(++childs);
			this.compAreaId(adminAreas, findStationAdminArea.getParentId(), ++repeatNum);
		} else if (repeatNum == 0) {
			return true;
			/*Collection<StationAdminArea> haAdminAreas = haAdminAreaDao.findAllWhere(stationAdminArea.getAdmauth().replace(" ", "")+"市");
			if(haAdminAreas.size()==1){
				return false;
			}else {
				return true;
			}*/
		}

		return false;
	}

	private Predicate<StationAdminArea> findPred(final String findKey) {
		return new Predicate<StationAdminArea>() {
			public boolean apply(StationAdminArea point) {
				String parentId = findKey;
				String id = point.getId();
				return Objects.equal(parentId, id);
			}
		};
	}

	@Override
	public void addStationArea(final Integer areaId, List<String> stations) {
		List<HaStationArea> haStationAreas = Lists.transform(stations,
				new Function<String, HaStationArea>() {
			public HaStationArea apply(String input) {
				return new HaStationArea(input, areaId);
			}
		});
		haStationAreaDao.insertBatch(haStationAreas);

		// 新建线程重新填充
		this.rePullAreaStatGroup();
	}

	@Override
	public void removeStationArea(Integer areaId, List<String> stations) {
		if (stations.isEmpty())
			return;

		HaStationAreaExample haStationAreaExample = new HaStationAreaExample();
		Criteria criteria = haStationAreaExample.createCriteria();
		criteria.andStationIdIn(stations);
		criteria.andAreaIdEqualTo(areaId);

		List<HaStationArea> stationAreas = haStationAreaDao
				.selectByExample(haStationAreaExample);

		List<Integer> statIds = Lists.transform(stationAreas,
				new Function<HaStationArea, Integer>() {
			public Integer apply(HaStationArea input) {
				return input.getId();
			}
		});

		HaStationStationGroupExample haStationStationGroupExample = new HaStationStationGroupExample();
		haStationStationGroupExample.createCriteria().andStatIdIn(statIds);
		// 删除 HaStationStationGroup 表中以
		// HaStationArea id 为statId 属性值的行
		haStationStationGroupDao.deleteByExample(haStationStationGroupExample);

		haStationAreaDao.deleteByExample(haStationAreaExample);

		// 新建线程重新填充
		this.rePullAreaStatGroup();
	}

	private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
	private ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 10, 1,
			TimeUnit.DAYS, queue);

	public void rePullAreaStatGroup() {
		executor.execute(new RePullAreaStatGroupThread());
	}

	private class RePullAreaStatGroupThread implements Runnable {
		@Override
		public void run() {
			StatGroupThreadLocal.setAreaStatGroupMap(getAreaStarGroupMap());
		}
	}

}